package com.elvin.wx.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.elvin.wx.beans.*;
import com.elvin.wx.service.UserOrganizeService;
import com.elvin.wx.service.UserRoleService;
import com.elvin.wx.service.UserService;
import com.elvin.wx.util.HttpUtil;
import com.elvin.wx.util.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.log4j.Log4j2;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.AlgorithmParameters;
import java.security.Security;
import java.util.*;

/**
 * @Classname MiniAppController
 * @Description 小程序登陆相关
 * @Date 2022/1/4 下午10:51
 * @Created by yuankeyan
 */
@Controller
@RestController
@Log4j2
@Api("小程序登陆")
public class MiniAppController {

    @Resource
    private UserService userService;

    @ApiOperation(value = "获取openId")
    @PostMapping("/getOpenId")
    //(@ApiParam("登陆code") @RequestParam("code") String code, @RequestParam("appId") String appId, @RequestParam("appSecret") String appSecret, @RequestParam("grantType") String grantType) {
    public Result<Object> getOpenId(@ApiParam("登陆code") @RequestParam("code") String code) {
        Result<Object> result = new Result<>();
        try {
            String appId = "wxd8dd4e82e253829f";
            //String appSecret = "07de2c401a531d8c30710e2fae105387";//by zcl 20220412
            String appSecret = "b78154bee673b9072ee16e4062d3c053";
            String grantType = "authorization_code";
            Map<String, String> requestUrlParam = new HashMap<>();
            requestUrlParam.put("appid", appId); // 开发者设置中的appId
            requestUrlParam.put("secret", appSecret); // 开发者设置中的appSecret
            requestUrlParam.put("js_code", code); // 小程序调用wx.login返回的code
            requestUrlParam.put("grant_type", grantType); // 默认参数
            JSONObject json = JSONObject.parseObject(HttpUtil.sendPost("https://api.weixin.qq.com/sns/jscode2session", requestUrlParam));
            log.debug("getOpenId json = {}", json);
            String sessionKey = json.getString("session_key");
            String openid = json.getString("openid");
            Map<String, String> resultMap = new HashMap<>();
            resultMap.put("sessionKey", sessionKey);
            resultMap.put("openid", openid);
            resultMap.put("json", json.toString());
            if (StringUtils.isEmpty(openid)) {
                result.fail(json, "请求出错");
            } else {
                result.success(resultMap);
            }
        } catch (Exception e) {
            log.debug(e.getMessage());
            result.fail(null, e.getMessage());
        }
        return result;
    }

    @ApiOperation(value = "解析手机号")
    @PostMapping("/parsePhoneNumber")
    public Result<Object> parsePhoneNumber(@RequestBody MainApp mainApp) {
        Result<Object> result = new Result<>();

        try {
            String userInfo = getUserInfo(mainApp.getEncryptedData(), mainApp.getIv(), mainApp.getSessionKey());
            JSONObject parseObject = JSONObject.parseObject(userInfo);
            log.debug("parsePhoneNumber parseObject = {}", parseObject);

            if (parseObject == null) {
                result.fail(null, "请求出错");
            } else {
                saveUserInfo(parseObject.getString("phoneNumber"), mainApp.getOpenId());
                UserInfo userRes = getUserInfoByOpenDb(mainApp.getOpenId());
                result.success(userRes);
            }
        } catch (Exception e) {
            log.debug(e.getMessage());
            result.fail(null, e.getMessage());
        }
        return result;
    }

    private String getUserInfo(String encryptedData, String iv, String sessionKey) {
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] dataByte = decoder.decode(encryptedData);
        byte[] keyByte = decoder.decode(sessionKey);
        byte[] ivByte = decoder.decode(iv);
        try {
            // 如果密钥不足16位，那么就补足. 这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, "UTF-8");
                return result;
            }
        } catch (Exception e) {
            log.debug(e.getMessage());
        }
        return null;
    }

    @Transactional
    public void saveUserInfo(String telephone, String openId) {
        EntityWrapper<User> wrapper = new EntityWrapper<>();
        wrapper.eq("telephone", telephone);
        User user = userService.selectOne(wrapper);
        if (user != null) {
            if (!openId.equals(user.getOpenid())) {
                User updateUser = new User();
                updateUser.setId(user.getId());
                updateUser.setOpenid(openId);
                userService.updateById(updateUser);
            }
        } else {
            User newUser = new User();
            newUser.setOpenid(openId);
            newUser.setTelephone(telephone);
            newUser.setRoleId(1);
            newUser.setOrganizeId(1);
            userService.insert(newUser);
        }
    }

    public UserInfo getUserInfoByOpenDb(String openId) {
        EntityWrapper<User> wrapper = new EntityWrapper<>();
        wrapper.eq("openid", openId);
        User userDb = userService.selectOne(wrapper);
        return new UserInfo(userDb);
    }

}
